Este relatório, tem como objetivo analisar dados de commits no github. Utilizaremos uma amostra de dados da atividade global do github entre o período de 01/2016 e 05/2017. As linguagens que vamos analisar serão java e javascript.
Aqui está sendo feita a importação dos dados e filtrando as liguagens que foram escolhidas para serem analisadas.
dados_github = read_csv(here("data/github-users-committing-filetypes.csv"),
progress = FALSE,
col_types = cols(file_extension = col_character(),
month_day = col_integer(),
the_month = col_integer(),
the_year = col_integer(),
users = col_integer())) %>%
filter(file_extension %in% c("java", "js"))
dados_github = dados_github %>%
mutate(date = paste(the_year, the_month, month_day, sep='-') %>% as.Date(.))
dados_github$weekday = weekdays(as.Date(dados_github$date))
dados_github = dados_github %>%
mutate(is_weekend = ifelse(weekday %in% c("sábado", "domingo"),TRUE, FALSE))
dados_java = dados_github %>%
filter(file_extension == "java")
dados_js = dados_github %>%
filter(file_extension == "js")
Antes de responder algumas perguntas, vamos dar uma olhada na linha do tempo das duas linguagens.
Ano de 2016
p =
dados_github %>%
filter(the_year == "2016") %>%
ggplot(aes(x=the_month,
y=users,
text = paste("Mês:",the_month,
"\nQuantidade de Usuários:",
users))) +
labs(y = "Quantidade de usuários", x = "Mês")+
theme(legend.position="none") +
geom_boxplot(colour = "#800000") + facet_wrap( ~ file_extension)
ggplotly(p, tooltip = "text")
Ano de 2017
p =
dados_github %>%
filter(the_year == "2017") %>%
ggplot(aes(x=the_month,
y=users,
text = paste("Mês:",the_month,
"\nQuantidade de Usuários:",
users))) +
labs(y = "Quantidade de usuários", x = "Mês")+
theme(legend.position="none") +
geom_boxplot(colour = "#003366") + facet_wrap( ~ file_extension)
ggplotly(p, tooltip = "text")
Observando os dois gráficos, verificamos que não há outliers.
Para cada uma delas, há uma diferença significativa na sua popularidade durante a semana e durante o fim de semana? Essa diferença é grande?
Para respondermos essa pergunta, precimas aplicar algumas técnicas de estatística. Primeiro, vamos utilizar o método de reamostragem chamado bootstrapping, ele é utilizado para aproximar distribuição na amostra de um levantamento estatístico. Após a aplicação desse método, o Intervalo de Confiança será calculado e assim poderemos inferir o resultado da amostra para toda a população.
Java
amostra_semana <- dados_java %>% filter(is_weekend == "FALSE") %>% sample_n(70)
amostra_semana <- rename(amostra_semana,users_semana = users)
amostra_fim_de_semana <- dados_java %>% filter(is_weekend == "TRUE") %>% sample_n(70)
amostra_fim_de_semana <- rename(amostra_fim_de_semana,users_fim_de_semana = users)
b <- bootstrap(amostra_semana, median(users_semana))
mediana_g1 <- CI.bca(b, probs = c(.05, .95))
mediana_g1
5% 95%
median(users_semana) 3477 3670.5
b <- bootstrap(amostra_fim_de_semana, median(users_fim_de_semana))
mediana_g2 <- CI.bca(b, probs = c(.05, .95))
mediana_g2
5% 95%
median(users_fim_de_semana) 2065 2181
Aqui, iremos utilizar uma confiança de 95% para verificar os diferentes intervalos:
df <- data.frame(rbind(mediana_g1,
mediana_g2))
df$medida = row.names(df)
df %>%
ggplot(aes(x = medida, ymin = X5., ymax = X95.)) +
geom_errorbar(width = .2)

Há claramente uma diferença entre a popularidade durante a semana e o fim de semana, os intervalos não se interceptaram e estão distantes.
Javascript
amostra_semana <- dados_js %>% filter(is_weekend == "FALSE") %>% sample_n(70)
amostra_semana <- rename(amostra_semana,users_semana = users)
amostra_fim_de_semana <- dados_js %>% filter(is_weekend == "TRUE") %>% sample_n(70)
amostra_fim_de_semana <- rename(amostra_fim_de_semana,users_fim_de_semana = users)
b <- bootstrap(amostra_semana, median(users_semana))
mediana_g1 <- CI.bca(b, probs = c(.05, .95))
mediana_g1
5% 95%
median(users_semana) 6853 7404
b <- bootstrap(amostra_fim_de_semana, median(users_fim_de_semana))
mediana_g2 <- CI.bca(b, probs = c(.05, .95))
mediana_g2
5% 95%
median(users_fim_de_semana) 4261 4549
Iremos utilizar o mesmo nível de confiança do experimento anterior (95%):
df <- data.frame(rbind(mediana_g1,
mediana_g2))
df$medida = row.names(df)
df %>%
ggplot(aes(x = medida, ymin = X5., ymax = X95.)) +
geom_errorbar(width = .2)

Os resultados são iguais os do experimento com a linguagem Java, apenas diferindo na quantidade de usuários, ou seja, durante o período de fim de semana a popularidade é menor.
Existe uma diferença significativa entre a popularidade das duas linguagens nos fins de semana?
Utilizaremos a mediana e a técnica do bootstrapping para responder essa pergunta. O nível de confiança utilizado será 95%.
amostra_java <- dados_java %>% filter(is_weekend == "TRUE") %>% sample_n(70)
amostra_java <- rename(dados_java,users_java = users)
amostra_js <- dados_js %>% filter(is_weekend == "TRUE") %>% sample_n(70)
amostra_js <- rename(dados_js,users_js = users)
b <- bootstrap(amostra_java, median(users_java))
media_java <- CI.bca(b, probs = c(.05, .95))
media_java
5% 95%
median(users_java) 3343 3441.5
b <- bootstrap(amostra_js, median(users_js))
View(df)
media_js <- CI.bca(b, probs = c(.05, .95))
media_js
5% 95%
median(users_js) 6648 6868
Vamos gerar o gráfico dos intervalos de confiança:
df <- data.frame(rbind(media_java,
media_js))
df$medida = row.names(df)
df %>%
ggplot(aes(x = medida, ymin = X5., ymax = X95.)) +
geom_errorbar(width = .05)

Mais uma vez, os intervalos estão distantes um do outro, mostrando que existe uma diferença significativa entre os usuários das duas linguagens durante o fim de semana.
LS0tCnRpdGxlOiAiRGFkb3MgZGUgY29tbWl0cyBubyBnaXRodWIiCmRhdGU6IDIwMTgtMDctMDcKYXV0aG9yOiAiTWFpbmFyYSBDYXZhbGNhbnRpIGRlIEZhcmlhcyIKb3V0cHV0OgogIGh0bWxfZG9jdW1lbnQ6CiAgICBkZl9wcmludDogcGFnZWQKICAgIHRvYzogeWVzCiAgICB0b2NfZmxvYXQ6IHllcwogIGh0bWxfbm90ZWJvb2s6CiAgICB0b2M6IHllcwogICAgdG9jX2Zsb2F0OiB5ZXMKLS0tCgpFc3RlIHJlbGF0w7NyaW8sIHRlbSBjb21vIG9iamV0aXZvIGFuYWxpc2FyIGRhZG9zIGRlIGNvbW1pdHMgbm8gZ2l0aHViLiBVdGlsaXphcmVtb3MgdW1hIGFtb3N0cmEgZGUgZGFkb3MgZGEgYXRpdmlkYWRlIGdsb2JhbCBkbyBnaXRodWIgZW50cmUgbyBwZXLDrW9kbyBkZSAwMS8yMDE2IGUgMDUvMjAxNy4gQXMgbGluZ3VhZ2VucyBxdWUgdmFtb3MgYW5hbGlzYXIgc2Vyw6NvICpqYXZhKiBlICpqYXZhc2NyaXB0Ki4KCgpgYGB7ciBzZXR1cCwgZWNobz1GQUxTRSwgd2FybmluZz1GQUxTRSwgbWVzc2FnZT1GQUxTRX0KbGlicmFyeSh0aWR5dmVyc2UpCmxpYnJhcnkoaGVyZSkKbGlicmFyeShwbG90bHkpCmxpYnJhcnkocmVzYW1wbGUsIHF1aWV0bHkgPSBUUlVFKQpgYGAKCkFxdWkgZXN0w6Egc2VuZG8gZmVpdGEgYSBpbXBvcnRhw6fDo28gZG9zIGRhZG9zIGUgZmlsdHJhbmRvIGFzIGxpZ3VhZ2VucyBxdWUgZm9yYW0gZXNjb2xoaWRhcyBwYXJhIHNlcmVtIGFuYWxpc2FkYXMuCmBgYHtyfQpkYWRvc19naXRodWIgPSByZWFkX2NzdihoZXJlKCJkYXRhL2dpdGh1Yi11c2Vycy1jb21taXR0aW5nLWZpbGV0eXBlcy5jc3YiKSwKICAgICAgICAgICAgICAgICAgICAgICAgcHJvZ3Jlc3MgPSBGQUxTRSwKICAgICAgICAgICAgICAgICAgICAgICAgY29sX3R5cGVzID0gY29scyhmaWxlX2V4dGVuc2lvbiA9IGNvbF9jaGFyYWN0ZXIoKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbW9udGhfZGF5ID0gY29sX2ludGVnZXIoKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGhlX21vbnRoID0gY29sX2ludGVnZXIoKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGhlX3llYXIgPSBjb2xfaW50ZWdlcigpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB1c2VycyA9IGNvbF9pbnRlZ2VyKCkpKSAlPiUgCiAgZmlsdGVyKGZpbGVfZXh0ZW5zaW9uICVpbiUgYygiamF2YSIsICJqcyIpKQoKYGBgCgoKYGBge3J9CmRhZG9zX2dpdGh1YiA9IGRhZG9zX2dpdGh1YiAlPiUgCiAgbXV0YXRlKGRhdGUgPSBwYXN0ZSh0aGVfeWVhciwgdGhlX21vbnRoLCBtb250aF9kYXksIHNlcD0nLScpICU+JSAgYXMuRGF0ZSguKSkKCmRhZG9zX2dpdGh1YiR3ZWVrZGF5ID0gd2Vla2RheXMoYXMuRGF0ZShkYWRvc19naXRodWIkZGF0ZSkpCgpkYWRvc19naXRodWIgPSBkYWRvc19naXRodWIgJT4lIAogIG11dGF0ZShpc193ZWVrZW5kID0gaWZlbHNlKHdlZWtkYXkgJWluJSBjKCJzw6FiYWRvIiwgImRvbWluZ28iKSxUUlVFLCBGQUxTRSkpCgpkYWRvc19qYXZhID0gZGFkb3NfZ2l0aHViICU+JSAKICBmaWx0ZXIoZmlsZV9leHRlbnNpb24gPT0gImphdmEiKQoKZGFkb3NfanMgPSBkYWRvc19naXRodWIgJT4lIAogIGZpbHRlcihmaWxlX2V4dGVuc2lvbiA9PSAianMiKQoKYGBgCgpBbnRlcyBkZSByZXNwb25kZXIgYWxndW1hcyBwZXJndW50YXMsIHZhbW9zIGRhciB1bWEgb2xoYWRhIG5hIGxpbmhhIGRvIHRlbXBvIGRhcyBkdWFzIGxpbmd1YWdlbnMuCgojIyMjIEFubyBkZSAyMDE2CgpgYGB7cn0KcCA9CiAgZGFkb3NfZ2l0aHViICU+JSAKICBmaWx0ZXIodGhlX3llYXIgPT0gIjIwMTYiKSAlPiUgCiAgZ2dwbG90KGFlcyh4PXRoZV9tb250aCwgCiAgICAgICAgICAgICB5PXVzZXJzLAogICAgICAgICAgICAgdGV4dCA9IHBhc3RlKCJNw6pzOiIsdGhlX21vbnRoLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIlxuUXVhbnRpZGFkZSBkZSBVc3XDoXJpb3M6IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHVzZXJzKSkpICsKICAgICBsYWJzKHkgPSAiUXVhbnRpZGFkZSBkZSB1c3XDoXJpb3MiLCB4ID0gIk3DqnMiKSsKICAgIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbj0ibm9uZSIpICsKICBnZW9tX2JveHBsb3QoY29sb3VyID0gIiM4MDAwMDAiKSArIGZhY2V0X3dyYXAoIH4gZmlsZV9leHRlbnNpb24pCmdncGxvdGx5KHAsIHRvb2x0aXAgPSAidGV4dCIpCmBgYAoKIyMjIyBBbm8gZGUgMjAxNwpgYGB7cn0KcCA9CiAgZGFkb3NfZ2l0aHViICU+JSAKICBmaWx0ZXIodGhlX3llYXIgPT0gIjIwMTciKSAlPiUgCiAgZ2dwbG90KGFlcyh4PXRoZV9tb250aCwgCiAgICAgICAgICAgICB5PXVzZXJzLAogICAgICAgICAgICAgdGV4dCA9IHBhc3RlKCJNw6pzOiIsdGhlX21vbnRoLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIlxuUXVhbnRpZGFkZSBkZSBVc3XDoXJpb3M6IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHVzZXJzKSkpICsKICAgICBsYWJzKHkgPSAiUXVhbnRpZGFkZSBkZSB1c3XDoXJpb3MiLCB4ID0gIk3DqnMiKSsKICAgIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbj0ibm9uZSIpICsKICBnZW9tX2JveHBsb3QoY29sb3VyID0gIiMwMDMzNjYiKSArIGZhY2V0X3dyYXAoIH4gZmlsZV9leHRlbnNpb24pCmdncGxvdGx5KHAsIHRvb2x0aXAgPSAidGV4dCIpCmBgYAoKT2JzZXJ2YW5kbyBvcyBkb2lzIGdyw6FmaWNvcywgdmVyaWZpY2Ftb3MgcXVlIG7Do28gaMOhIG91dGxpZXJzLgoKIyMjIFBhcmEgY2FkYSB1bWEgZGVsYXMsIGjDoSB1bWEgZGlmZXJlbsOnYSBzaWduaWZpY2F0aXZhIG5hIHN1YSBwb3B1bGFyaWRhZGUgZHVyYW50ZSBhIHNlbWFuYSBlIGR1cmFudGUgbyBmaW0gZGUgc2VtYW5hPyBFc3NhIGRpZmVyZW7Dp2Egw6kgZ3JhbmRlPwoKUGFyYSByZXNwb25kZXJtb3MgZXNzYSBwZXJndW50YSwgcHJlY2ltYXMgYXBsaWNhciBhbGd1bWFzIHTDqWNuaWNhcyBkZSBlc3RhdMOtc3RpY2EuIFByaW1laXJvLCB2YW1vcyB1dGlsaXphciBvIG3DqXRvZG8gZGUgcmVhbW9zdHJhZ2VtIGNoYW1hZG8gKmJvb3RzdHJhcHBpbmcqLCBlbGUgw6kgdXRpbGl6YWRvIHBhcmEgYXByb3hpbWFyIGRpc3RyaWJ1acOnw6NvIG5hIGFtb3N0cmEgZGUgdW0gbGV2YW50YW1lbnRvIGVzdGF0w61zdGljby4gQXDDs3MgYSBhcGxpY2HDp8OjbyBkZXNzZSBtw6l0b2RvLCBvICpJbnRlcnZhbG8gZGUgQ29uZmlhbsOnYSogc2Vyw6EgY2FsY3VsYWRvIGUgYXNzaW0gcG9kZXJlbW9zIGluZmVyaXIgbyByZXN1bHRhZG8gZGEgYW1vc3RyYSBwYXJhIHRvZGEgYSBwb3B1bGHDp8Ojby4KCiMjIyMgSmF2YQoKCmBgYHtyfQphbW9zdHJhX3NlbWFuYSA8LSBkYWRvc19qYXZhICU+JSAgZmlsdGVyKGlzX3dlZWtlbmQgPT0gIkZBTFNFIikgJT4lIHNhbXBsZV9uKDcwKQphbW9zdHJhX3NlbWFuYSA8LSByZW5hbWUoYW1vc3RyYV9zZW1hbmEsdXNlcnNfc2VtYW5hID0gdXNlcnMpCgphbW9zdHJhX2ZpbV9kZV9zZW1hbmEgPC0gZGFkb3NfamF2YSAlPiUgIGZpbHRlcihpc193ZWVrZW5kID09ICJUUlVFIikgJT4lIHNhbXBsZV9uKDcwKQphbW9zdHJhX2ZpbV9kZV9zZW1hbmEgPC0gcmVuYW1lKGFtb3N0cmFfZmltX2RlX3NlbWFuYSx1c2Vyc19maW1fZGVfc2VtYW5hID0gdXNlcnMpCgpiIDwtIGJvb3RzdHJhcChhbW9zdHJhX3NlbWFuYSwgbWVkaWFuKHVzZXJzX3NlbWFuYSkpCm1lZGlhbmFfZzEgPC0gQ0kuYmNhKGIsIHByb2JzID0gYyguMDUsIC45NSkpCm1lZGlhbmFfZzEKYiA8LSBib290c3RyYXAoYW1vc3RyYV9maW1fZGVfc2VtYW5hLCBtZWRpYW4odXNlcnNfZmltX2RlX3NlbWFuYSkpCm1lZGlhbmFfZzIgPC0gQ0kuYmNhKGIsIHByb2JzID0gYyguMDUsIC45NSkpCm1lZGlhbmFfZzIKYGBgCgpBcXVpLCBpcmVtb3MgdXRpbGl6YXIgdW1hIGNvbmZpYW7Dp2EgZGUgOTUlIHBhcmEgdmVyaWZpY2FyIG9zIGRpZmVyZW50ZXMgaW50ZXJ2YWxvczoKCmBgYHtyfQpkZiA8LSBkYXRhLmZyYW1lKHJiaW5kKG1lZGlhbmFfZzEsIAogICAgICAgICAgICAgICAgICAgICAgbWVkaWFuYV9nMikpCmRmJG1lZGlkYSA9IHJvdy5uYW1lcyhkZikKZGYgJT4lIAogIGdncGxvdChhZXMoeCA9IG1lZGlkYSwgeW1pbiA9IFg1LiwgeW1heCA9IFg5NS4pKSArIAogIGdlb21fZXJyb3JiYXIod2lkdGggPSAuMikKYGBgCgpIw6EgY2xhcmFtZW50ZSB1bWEgZGlmZXJlbsOnYSBlbnRyZSBhIHBvcHVsYXJpZGFkZSBkdXJhbnRlIGEgc2VtYW5hIGUgbyBmaW0gZGUgc2VtYW5hLCBvcyBpbnRlcnZhbG9zIG7Do28gc2UgaW50ZXJjZXB0YXJhbSBlIGVzdMOjbyBkaXN0YW50ZXMuCgoKIyMjIyBKYXZhc2NyaXB0CgpgYGB7cn0KYW1vc3RyYV9zZW1hbmEgPC0gZGFkb3NfanMgJT4lICBmaWx0ZXIoaXNfd2Vla2VuZCA9PSAiRkFMU0UiKSAlPiUgc2FtcGxlX24oNzApCmFtb3N0cmFfc2VtYW5hIDwtIHJlbmFtZShhbW9zdHJhX3NlbWFuYSx1c2Vyc19zZW1hbmEgPSB1c2VycykKCmFtb3N0cmFfZmltX2RlX3NlbWFuYSA8LSBkYWRvc19qcyAlPiUgIGZpbHRlcihpc193ZWVrZW5kID09ICJUUlVFIikgJT4lIHNhbXBsZV9uKDcwKQphbW9zdHJhX2ZpbV9kZV9zZW1hbmEgPC0gcmVuYW1lKGFtb3N0cmFfZmltX2RlX3NlbWFuYSx1c2Vyc19maW1fZGVfc2VtYW5hID0gdXNlcnMpCgpiIDwtIGJvb3RzdHJhcChhbW9zdHJhX3NlbWFuYSwgbWVkaWFuKHVzZXJzX3NlbWFuYSkpCm1lZGlhbmFfZzEgPC0gQ0kuYmNhKGIsIHByb2JzID0gYyguMDUsIC45NSkpCm1lZGlhbmFfZzEKYiA8LSBib290c3RyYXAoYW1vc3RyYV9maW1fZGVfc2VtYW5hLCBtZWRpYW4odXNlcnNfZmltX2RlX3NlbWFuYSkpCm1lZGlhbmFfZzIgPC0gQ0kuYmNhKGIsIHByb2JzID0gYyguMDUsIC45NSkpCm1lZGlhbmFfZzIKYGBgCgpJcmVtb3MgdXRpbGl6YXIgbyBtZXNtbyBuw612ZWwgZGUgY29uZmlhbsOnYSBkbyBleHBlcmltZW50byBhbnRlcmlvciAoOTUlKToKCmBgYHtyfQpkZiA8LSBkYXRhLmZyYW1lKHJiaW5kKG1lZGlhbmFfZzEsIAogICAgICAgICAgICAgICAgICAgICAgbWVkaWFuYV9nMikpCmRmJG1lZGlkYSA9IHJvdy5uYW1lcyhkZikKZGYgJT4lIAogIGdncGxvdChhZXMoeCA9IG1lZGlkYSwgeW1pbiA9IFg1LiwgeW1heCA9IFg5NS4pKSArIAogIGdlb21fZXJyb3JiYXIod2lkdGggPSAuMikKYGBgCgpPcyByZXN1bHRhZG9zIHPDo28gaWd1YWlzIG9zIGRvIGV4cGVyaW1lbnRvIGNvbSBhIGxpbmd1YWdlbSAqSmF2YSosIGFwZW5hcyBkaWZlcmluZG8gbmEgcXVhbnRpZGFkZSBkZSB1c3XDoXJpb3MsIG91IHNlamEsIGR1cmFudGUgbyBwZXLDrW9kbyBkZSBmaW0gZGUgc2VtYW5hIGEgcG9wdWxhcmlkYWRlIMOpIG1lbm9yLgoKCiMjIyBFeGlzdGUgdW1hIGRpZmVyZW7Dp2Egc2lnbmlmaWNhdGl2YSBlbnRyZSBhIHBvcHVsYXJpZGFkZSBkYXMgZHVhcyBsaW5ndWFnZW5zIG5vcyBmaW5zIGRlIHNlbWFuYT8KClV0aWxpemFyZW1vcyBhIG1lZGlhbmEgZSBhIHTDqWNuaWNhIGRvICpib290c3RyYXBwaW5nKiBwYXJhIHJlc3BvbmRlciBlc3NhIHBlcmd1bnRhLiBPIG7DrXZlbCBkZSBjb25maWFuw6dhIHV0aWxpemFkbyBzZXLDoSA5NSUuCgpgYGB7cn0KYW1vc3RyYV9qYXZhIDwtIGRhZG9zX2phdmEgJT4lICBmaWx0ZXIoaXNfd2Vla2VuZCA9PSAiVFJVRSIpICU+JSBzYW1wbGVfbig3MCkKYW1vc3RyYV9qYXZhIDwtIHJlbmFtZShkYWRvc19qYXZhLHVzZXJzX2phdmEgPSB1c2VycykKCmFtb3N0cmFfanMgPC0gZGFkb3NfanMgJT4lICBmaWx0ZXIoaXNfd2Vla2VuZCA9PSAiVFJVRSIpICU+JSBzYW1wbGVfbig3MCkKYW1vc3RyYV9qcyA8LSByZW5hbWUoZGFkb3NfanMsdXNlcnNfanMgPSB1c2VycykKCmIgPC0gYm9vdHN0cmFwKGFtb3N0cmFfamF2YSwgbWVkaWFuKHVzZXJzX2phdmEpKQptZWRpYV9qYXZhIDwtIENJLmJjYShiLCBwcm9icyA9IGMoLjA1LCAuOTUpKQptZWRpYV9qYXZhCmIgPC0gYm9vdHN0cmFwKGFtb3N0cmFfanMsIG1lZGlhbih1c2Vyc19qcykpCm1lZGlhX2pzIDwtIENJLmJjYShiLCBwcm9icyA9IGMoLjA1LCAuOTUpKQptZWRpYV9qcwpgYGAKClZhbW9zIGdlcmFyIG8gZ3LDoWZpY28gZG9zIGludGVydmFsb3MgZGUgY29uZmlhbsOnYToKCmBgYHtyfQpkZiA8LSBkYXRhLmZyYW1lKHJiaW5kKG1lZGlhX2phdmEsIAogICAgICAgICAgICAgICAgICAgICAgbWVkaWFfanMpKQpkZiRtZWRpZGEgPSByb3cubmFtZXMoZGYpCmRmICU+JSAKICBnZ3Bsb3QoYWVzKHggPSBtZWRpZGEsIHltaW4gPSBYNS4sIHltYXggPSBYOTUuKSkgKyAKICBnZW9tX2Vycm9yYmFyKHdpZHRoID0gLjA1KQoKYGBgCgpNYWlzIHVtYSB2ZXosIG9zIGludGVydmFsb3MgZXN0w6NvIGRpc3RhbnRlcyB1bSBkbyBvdXRybywgbW9zdHJhbmRvIHF1ZSBleGlzdGUgdW1hIGRpZmVyZW7Dp2Egc2lnbmlmaWNhdGl2YSBlbnRyZSBvcyB1c3XDoXJpb3MgZGFzIGR1YXMgbGluZ3VhZ2VucyBkdXJhbnRlIG8gZmltIGRlIHNlbWFuYS4KCg==